package elitequant.data;

import static elitequant.util.UtilFunc.parseDate;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import elitequant.util.UtilFunc;

/**
 * BacktestDataFeed retrieves historical data; which is pulled out by backtest_event_engine.
 *
 */
public class BacktestDataFeedLocal extends DataFeedBase {
    
    private final static String CSV_CHARSET = "UTF-8";
	
	private String histDir;
	private String startDate;
	private String endDate;
    private List<BarEvent> histData;
    private Iterator<BarEvent> dataStream;
	
	public BacktestDataFeedLocal(String histDir, String startDate, String endDate){
		this.histDir = histDir;
		
		Calendar c = Calendar.getInstance();
		
		if(endDate != null && endDate.trim().length() > 0){
			this.endDate = endDate;
		}
		else{
			this.endDate = UtilFunc.getTodayFormat();
		}
		
		if(startDate != null && startDate.trim().length() > 0){
			this.startDate = startDate;
		}
		else{
			this.startDate = UtilFunc.getLaterFormat(-365);
		}

        histData = new ArrayList<BarEvent>();
	}

    private void retrieveHistoricalData(String symbol){

        Date start = parseDate(startDate);
        Date end = parseDate(endDate);
        
        File histFile = new File(histDir, String.format("%s.csv", symbol));
        
        try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(histFile), CSV_CHARSET))) {
            // read metadata
            String[] header = reader.readLine().split(",");
            Map<String, Integer> headerIndexMap = new HashMap<String, Integer>();
            for(int i = 0; i < header.length; i++) {
                headerIndexMap.put(header[i], i);
            }
            
            String line = null;
            while((line = reader.readLine()) != null) {
                String[] row = line.split(",");
                
                // filter data 
                Date date = UtilFunc.parseDate(row[headerIndexMap.get("Date")]);
                if((start != null && date.compareTo(start) < 0) 
                        || (end != null && date.compareTo(end) > 0)){
                    continue;
                }
                
                BarEvent bar = new BarEvent();
                bar.fullSymbol = symbol;
                bar.interval = 86400;
                bar.barStartTime = date;
                bar.openPrice = new BigDecimal(row[headerIndexMap.get("Open")]);
                bar.highPrice = new BigDecimal(row[headerIndexMap.get("High")]);
                bar.closePrice = new BigDecimal(row[headerIndexMap.get("Close")]);
                bar.lowPrice = new BigDecimal(row[headerIndexMap.get("Low")]);
                bar.volume = new BigDecimal(row[headerIndexMap.get("Volume")]).intValue();
                bar.adjClosePrice = new BigDecimal(row[headerIndexMap.get("Adj Close")]);
                histData.add(bar);
            }
                
        } catch (Exception e) {
            System.out.println(String.format("get local data error, %s", e.getMessage()));
        }

    }

    @Override
    public void subscribeMarketData(String[] symbols) {
        if(symbols != null) {
            for(String sym : symbols) {
                retrieveHistoricalData(sym);
            }
        }
        
        // order by
        histData.sort((bar1, bar2) -> {
            return bar1.barStartTime.compareTo(bar2.barStartTime);
        });
        
        dataStream = histData.iterator();
    }

    @Override
    public void unsubscribeMarketData(String[] symbols) {
        // do nothing
        
    }

    @Override
    public BarEvent streamNext() {
        if(dataStream.hasNext()) {
            return dataStream.next();
        }
        else {
            return null;
        }
    }
    

}
